Program Listing for File tsdeque.h
↰ Return to documentation for file (codes/cubicle_detect/darknet_ros/tsdeque.h
)
/*
This file is part of spixel.
Spixel is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Foobar is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vector>
#include <unordered_set>
#include <mutex>
// ParallelDeque
// - Thread safe deque based on vector ("circular list" representation)
// - Supports forbidden elements (excluded from PopFront operation)
// - Operations:
// * PopAndLock pops an "unforbidden" element from the front of the deque
// and locks it
// * Release releases element (removes it from forbidden list)
// * PushBack adds an element to the end of the deque.
template <typename T, typename S> class ParallelDeque {
private:
typedef std::unordered_set<S> LockSetType;
typedef std::unordered_map<T, LockSetType> LockMapType;
std::vector<T> vector;
size_t start;
size_t end;
size_t listSize;
size_t popCount;
T emptyVal;
std::function<void(T&, LockSetType&)> lockFun;
LockMapType lockMap;
LockSetType locked;
std::mutex m;
public:
ParallelDeque(size_t maxSize) :
start(0), end(0), listSize(0), emptyVal(T()),
popCount(0)
{
vector.resize(maxSize);
}
size_t GetPopCount() { return popCount; }
void SetEmptyVal(const T& ev) { emptyVal = ev; }
void SetLockFunction(const std::function<void(T&, LockSetType&)>& lf)
{
lockFun = lf;
}
size_t Size() const { return listSize; }
bool Empty() const {
return listSize == 0;
}
void Clear() { start = end = listSize = 0; }
void PushBack(const T& value)
{
std::unique_lock<std::mutex> lck(m);
if ((end + 1) % vector.size() == start) resize(2 * vector.size());
vector[end] = value;
end = (end + 1) % vector.size();
listSize++;
}
T PopAndLock()
{
std::unique_lock<std::mutex> lck(m);
LockSetType lockSet;
if (Empty()) return emptyVal;
for (int i = start; i != end; i = (i + 1) % vector.size()) {
T result = vector[i];
if (result != emptyVal) {
lockSet.clear();
lockFun(result, lockSet);
if (find_if(lockSet.begin(), lockSet.end(), [&](const S& s) { return locked.find(s) != locked.end(); }) == lockSet.end()) {
vector[i] = emptyVal;
if (i == start) {
do {
start = (start + 1) % vector.size();
} while (start != end && vector[start] == emptyVal);
}
locked.insert(lockSet.begin(), lockSet.end());
lockMap[result] = std::move(lockSet);
listSize--;
popCount++;
return result;
}
}
}
return emptyVal;
}
void Release(const T& e) {
std::unique_lock<std::mutex> lck(m);
typename LockMapType::iterator fiter = lockMap.find(e);
if (fiter != lockMap.end()) {
for (const S& s : fiter->second)
locked.erase(s);
lockMap.erase(e);
}
}
private:
void resize(size_t newSize)
{
std::vector<T> newVector;
assert(newSize > vector.size());
newVector.resize(newSize);
if (start <= end) std::copy(vector.begin() + start, vector.begin() + end, newVector.begin());
else {
std::copy(vector.begin() + start, vector.end(), newVector.begin());
std::copy(vector.begin(), vector.begin() + end, newVector.begin() + vector.size() - start);
}
std::swap(vector, newVector);
start = 0;
end = listSize;
}
};
template <typename T> class Deque {
private:
std::vector<T> vector;
size_t start;
size_t end;
size_t listSize;
public:
Deque(size_t maxSize) :
start(0), end(0), listSize(0)
{
vector.resize(maxSize);
}
size_t Size() const { return listSize; }
bool Empty() const { return listSize == 0; }
void Clear() { start = end = listSize = 0; }
void PushBack(const T& value)
{
if ((end + 1) % vector.size() == start) resize(2 * vector.size());
vector[end] = value;
end = (end + 1) % vector.size();
listSize++;
}
const T& Front() const { return vector[start]; }
T PopFront()
{
size_t retIndex = start;
start = (start + 1) % vector.size();
listSize--;
return vector[retIndex];
}
private:
void resize(size_t newSize)
{
std::vector<T> newVector;
assert(newSize > vector.size());
newVector.resize(newSize);
if (start <= end) std::copy(vector.begin() + start, vector.begin() + end, newVector.begin());
else {
std::copy(vector.begin() + start, vector.end(), newVector.begin());
std::copy(vector.begin(), vector.begin() + end, newVector.begin() + vector.size() - start);
}
std::swap(vector, newVector);
start = 0;
end = listSize;
}
};